import { Loading } from 'element-ui'
import Vue from 'vue'
import xss, {getDefaultCSSWhiteList} from 'xss'
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
// 观察者模式
const Observer = (function () {
    let message = {};
    function register(types, listener) {
        eachType(types, function(listeners){
            if(listeners.indexOf(listener) === -1)listeners.push(listener);
        });
    }
    function fire(types) {
        let args = [].slice.call(arguments, 1);
        eachType(types, function (listeners) {
            for (let j = 0; j < listeners.length; j++) {
                let fn = listeners[j];
                if (fn.apply(this, args) === true) {
                    return true;
                }
                if (listeners[j] !== fn) j--;
            }
        });
    }
    function remove(types, listener) {
        eachType(types, function(listeners) {
            let index = listeners.indexOf(listener);
            if(index !== -1) listeners.splice(index, 1);
            else listeners.splice(0, listeners.length);
        });
    }
    function getListeners(type) {
        type = type.toLowerCase();
        return message[type] || (message[type] = []);
    }
    function eachType(types, fn) {
        types = types.replace(/(^\s+)|(\s+$)/g, '').split(/\s+/);
        for (let i = 0, type; type = types[i++];) {
            let listeners = getListeners(type);
            fn(listeners);
        }
    }
    return {
        register: register,
        fire: fire,
        remove: remove,
        getAll:() => {
            return message;
        }
    }
})();
// 节流器
// 其实这是去抖，并不是节流
// 有空改成debounce，没空就算了
const throttle = (func, limit) => {
    let inThrottle,
      lastFunc,
      throttleTimer;
    return function () {
        let content = this,
          args = arguments;
        if (inThrottle) {
            clearTimeout(lastFunc);
            return lastFunc = setTimeout(function () {
                func.apply(content, args);
                inThrottle = false;
            }, limit);
        } else {
            func.apply(content, args);
            inThrottle = true;
            return throttleTimer = setTimeout(function () {
                return inThrottle = false;
            }, limit);
        }
    };
};
// 这个是节流函数，不是去抖
// function throttle(method, mustRunDelay) {
//     let timer,
//         args = arguments,
//         start;
//     return function loop() {
//         let self = this;
//         let now = Date.now();
//         if(!start){
//             start = now;
//         }
//         if(timer){
//             clearTimeout(timer);
//         }
//         if(now - start >= mustRunDelay){
//             method.apply(self, args);
//             start = now;
//         }else {
//             timer = setTimeout(function () {
//                 loop.apply(self, args);
//             }, 50);
//         }
//     }
// }
// 生成guid
const generateGuid = () => {
    let s = [];
    let hexDigits = "0123456789abcdef";
    for (let i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    return s.join("");
}
// 空方法
const noop = () => {}

// 判断是否满屏
function notFullScreen() {
    return (document.fullScreenElement !== undefined && document.fullScreenElement === null) || (document.msFullscreenElement !== undefined && document.msFullscreenElement === null) || (document.mozFullScreen !== undefined && !document.mozFullScreen) || (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen);
}
// 切换满屏
function toggleFullScreen(elem) {
    // ## The below if statement seems to work better ## if ((document.fullScreenElement && document.fullScreenElement !== null) || (document.msfullscreenElement && document.msfullscreenElement !== null) || (!document.mozFullScreen && !document.webkitIsFullScreen)) {
    if (notFullScreen()) {
        if (elem.requestFullScreen) {
            elem.requestFullScreen();
        } else if (elem.mozRequestFullScreen) {
            elem.mozRequestFullScreen();
        } else if (elem.webkitRequestFullScreen) {
            elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
        } else if (elem.msRequestFullscreen) {
            elem.msRequestFullscreen();
        }
    } else {
        if (document.cancelFullScreen) {
            document.cancelFullScreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.webkitCancelFullScreen) {
            document.webkitCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        }
    }
}

// 遍历树
const traverse = (arr, cb, pid, depth) => {
  arr = arr || [];
  depth = $.isNumeric(depth) ? depth : 1;
  for(let i = 0, len = arr.length; i < len; i++) {
    cb(arr[i], pid, i, depth);
    traverse(arr[i].children || arr[i].childList || [], cb, arr[i].id, depth + 1);
  }
}

// 比较是否相同
const equals = function (x, y) {
    var typeX = Object.prototype.toString.call(x),
        typeY = Object.prototype.toString.call(y);
    if (typeX !== typeY) return false;
    if (typeX === '[object Array]') {
        if (x.length !== y.length) return false;
        for (var i = 0, len = x.length; i < len; i++) {
            if (!equals(x[i], y[i])) return false;
        }
    } else if (typeX === '[object Object]') {
        var key;
        for (key in x) {
            if (x.hasOwnProperty(key) !== y.hasOwnProperty(key)) return false;
        }
        for (key in y) {
            if (x.hasOwnProperty(key) !== y.hasOwnProperty(key)) return false;
            if (!equals(x[key], y[key])) return false;
        }
    } else if (typeX === '[object RegExp]' || typeY === '[object Function]') {
        return x.toString() === y.toString();
    } else if (x !== y) {
        return false;
    }
    return true;
}

const getUrlParam = function (name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var r = window.location.search.substr(1).match(reg);
    if (r != null) return unescape(r[2]); return null;
}

// 双击
const doubleClick = function (doubleClk) {
    var alreadyclicked = false,
        alreadyclickedTimeout;

    return function (e) {
        if (alreadyclicked) {
            // double
            alreadyclicked = false;
            alreadyclickedTimeout && clearTimeout(alreadyclickedTimeout);
            doubleClk && doubleClk.call(this, e);
        } else {
            // single
            alreadyclicked = true;
            alreadyclickedTimeout = setTimeout(function () {
                alreadyclicked = false;
            }, 300);
        }
    }
}

// 根据在数组中找到对应的对象
const findIndex = (arr, key, value) => {
    for(let i = 0, len = arr.length; i < len; i++) {
        if(arr[i][key] === value) return i;
    }
    return -1;
}

const toLowerCaseObjKey = (obj) => {
    for (var key in obj) {
        var str = key.replace(/^\S/, function (s) { return s.toLowerCase() });
        if (str !== key) {
            obj[str] = obj[key];
            delete obj[key];
        }
        if (Array.isArray(obj[str]) || Object.prototype.toString.call(obj[str]) === '[object Object]') {
            obj[str] = toLowerCaseObjKey(obj[str]);
        }
    }
    return obj;
}

let loadingInstance;
let loadingTimer;

const loading = (immediate) => {
    let fn = () => {
        if(loadingInstance) return;
        loadingInstance = Loading.service({
            customClass: 'loading'
        })
    };
    if(immediate) fn();
    else loadingTimer = setTimeout(fn, 200);
}

const closeLoading = () => {
    clearTimeout(loadingTimer);
    if(loadingInstance) {
        Vue.nextTick(() => {
            loadingInstance.close();
            loadingInstance = null;
        });
    }
}

const getOffsetTopById = (node, id) => {
    let top = 0;
    while(node && node.offsetParent && node.id !== id) {
        top += node.offsetTop;
        node = node.offsetParent;
    }
    return top;
}

const removeMark = (mark) => {
    mark = $(mark);
    for(let i = mark.length-1; i >= 0; i--) {
        let node = mark[i];
        let p = node.parentNode;
        let next = node.nextSibling;
        while(node.childNodes.length) {
            p.insertBefore(node.childNodes[0], next);
        }
        $(node).remove();
    }
}
// 滚动至屏幕中
/**
 * @params dom {HTMLElement} - 要移动的元素
 * @params scrollDom {HTMLElement} - 含有滚动条的元素
 * @params extraOffset {Object} - 额外添加的offset
 */
const scrollToScreen = (dom, scrollDom, extraDom) => {
  scrollDom = $(scrollDom);
  dom = $(dom);
  if(!dom.length || !scrollDom.length) return;
  let domOffset = dom.offset();
  extraDom = $(extraDom);
  if(extraDom.length) {
    let extraOffset = extraDom.offset();
    domOffset.top += extraOffset.top;
    domOffset.left += extraOffset.left;
  }
  let scrollDomOffset = scrollDom.offset();
  let outerHeight = extraDom.length ? extraDom.outerHeight() : dom.outerHeight();
  if(domOffset.top - scrollDomOffset.top < 0) {
    scrollDom.scrollTop(scrollDom.scrollTop() + domOffset.top - scrollDomOffset.top);
  } else if(domOffset.top - scrollDomOffset.top + outerHeight > scrollDom.outerHeight()) {
    scrollDom.scrollTop(scrollDom.scrollTop() + domOffset.top - scrollDomOffset.top + outerHeight - scrollDom.outerHeight() + 5);
  }
}

const isUndefined = data => typeof data === 'undefined';

// 给String添加方法
String.prototype.format = function () {
    if (arguments.length === 0) return this.toString();
    var args = Array.prototype.slice.call(arguments);
    return this.replace(/\{(\d+)\}/g, function (m, i) {
        return args[i];
    });
};

String.prototype.htmlEscape = function () {
    return this.replace(/[<>&"]/g, function (c) { return { '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;' }[c]; });
};

String.prototype.trim = String.prototype.trim || function () {
    return this.replace(/(^\s*)|(\s*$)/g, "");
};

// 得到当前保存的时间
const getCurTime = () => {
    // return new Date().toLocaleString();
    let now = new Date()
        , year = now.getFullYear()
        , month = now.getMonth() + 1
        , date = now.getDate()
        , hour = now.getHours()
        , min = now.getMinutes()
        , sec = now.getSeconds();
    month = month < 10 ? `0` + month : month;
    date = date < 10 ? `0` + date : date;
    hour = hour < 10 ? `0` + hour : hour;
    min = min < 10 ? `0` + min : min;
    sec = sec < 10 ? `0` + sec : sec;
    return `${year}/${month}/${date} ${hour}:${min}`;
}

const myxss = (html) => {
    const cssWhiteList = getDefaultCSSWhiteList();
    cssWhiteList['line-height'] = true;

    return xss(html, {
        whiteList: UEDITOR_CONFIG.whitList,
        css: {
            whiteList: cssWhiteList
        }
    });
}
window.observer = Observer;
// 资源区域可拖动
function Resize(config) {
    this.isMoving = false;
    this.target = $("#" + config.targetID);
    this.controller = $("#" + config.controllerID);
    this.cover = $("#" + config.coverID);
    this.leftArea = $("#" + config.leftAreaID);
    this.bookArea = $("#" + config.bookAreaID);
    this.MAX_WIDTH = config.maxWidth || 800;
    this.MIN_WIDTH = config.minWidth || 200;
    this.bookResize = config.bookResize || 600;
    this.originalWidth = null;
    this.originalX = null;
}
Resize.prototype = {
    init() {
        let me = this;
        me.controller.on('mousedown', function (e) {
            me.start(e);
        })
        me.cover.mousemove(function (e) {
            if(me.isMoving){
                me.dragging(e);
            }
        }).mouseup(function (e) {
            if (me.isMoving) {
                me.end(e);
            }
        });
    },
    reCal(e) {
        let me = this;
        var reWidth = me.originalX - e.pageX + me.originalWidth;
        if(reWidth >= me.MAX_WIDTH) {
            return me.MAX_WIDTH;
        }else if(reWidth <= me.MIN_WIDTH){
            return me.MIN_WIDTH;
        }
        return reWidth;
    },
    // 控件mousedown的时候，开始
    // 1. 修改拖动状态标识符
    // 2. 记录当前的鼠标位置和宽度
    // 3. 打开cover层
    // 4. 关闭动画
    start(e){
        let me = this;
        me.isMoving = true; // 是否在移动的标识符
        me.originalWidth = me.target.width();
        me.originalX = e.pageX;
        me.target.addClass('dragging');
        me.leftArea.addClass('dragging');
        me.cover.show();
    },
    // 拖动过程中
    // 1. 重新计算宽度和定位
    // 2. 左侧区域变化
    // 3. 仿真书样式变化
    dragging(e){
        let me = this;
        let newWidth = me.reCal(e);
        me.target.css({
            'width': newWidth,
            'margin-right': -newWidth
        });
        if(newWidth >= me.bookResize){
            me.bookArea.css({
                "margin": "20px auto"
            });
        } else {
            me.bookArea.css({
                'margin': '10px 0 0 10px'
            });
        }
        me.changeLeftArea(newWidth);
    },
    // 结束
    // 1. 修改拖动状态标识符
    // 2. 关闭cover层
    // 3. 开启动画
    end(e){
        let me = this;
        // mouseup，清空，重置
        me.isMoving = false;
        me.cover.hide();
        me.target.removeClass('dragging');
        me.leftArea.removeClass('dragging');
    },
    showController(){
        this.controller.show();
    },
    hideController(){
        this.controller.hide();
    },
    // 修改左侧区域的位置
    changeLeftArea(arg){
        let me = this;
        switch (arg) {
            case 'afterRightOpen':
                // 右侧打开，左侧区域调整样式
                this.leftArea.css({
                    right: me.target.width()
                });
                break;
            case 'afterRightClose':
                // 右侧关闭，左侧区域调整样式
                this.leftArea.css({
                    right: 0
                });
                break;
            default:
                this.leftArea.css({
                    right: arg
                })
        }
    }
}
/**
 * 获取文件的格式
 * @param str 文件名全程
 * @param dotFlag 返回值是否带`.`
 * @param formatFlag 返回值是否需要转换成全大写或全小写 U==uppercase L==lowercase
 */
const getFileType = (str, dotFlag = true, formatFlag = "U") => {
    let index = str.lastIndexOf(".");
    if(dotFlag === false){
        index++;
    }
    switch (formatFlag) {
        case "U":
            return str.substr(index).toUpperCase();
        case "L":
            return str.substr(index).toLowerCase();
    }
}
/**
 * 获取文件的名称
 */
const getFileRawName = (str) => {
    return str.substring(0, str.lastIndexOf("."));
}
/**
 * 返回/api/file/down接口的完整地址
 */
const getFileDownUrl = () => {
    return globalVar.SITEORIGIN + window.apiurl + '/api/File/ShowFile?filecode='
}
/**
 * 返回腾讯视频iframe地址
 */
const getTencentIfrSrc = (fileId) => {
    return `//${globalVar.tencent_appid}.vod2.myqcloud.com/vod-player/${globalVar.tencent_appid}/${fileId}/tcplayer/console/vod-player.html?autoplay=false&width=1920&height=1080`;
}

export {
    Observer,
    throttle,
    generateGuid,
    noop,
    notFullScreen,
    toggleFullScreen,
    traverse,
    equals,
    doubleClick,
    getUrlParam,
    findIndex,
    toLowerCaseObjKey,
    loading,
    closeLoading,
    getOffsetTopById,
    removeMark,
    scrollToScreen,
    isUndefined,
    myxss,
    getCurTime,
    Resize,
    getFileType,
    getFileRawName,
    getFileDownUrl,
    getTencentIfrSrc
}
export default {
    install(Vue) {
        Vue.prototype.getPdf = ({title, content, editor}) => {
            let quoteDom = document.querySelector("#quoteList");
            if(quoteDom.lastElementChild.children.length > 0){
                // 有参考文献
                content += quoteDom.innerHTML;
            }
            let layerIndex = layer.open({
                type: 1,
                shade: false,
                resize: false,
                maxmin: false, //开启最大化最小化按钮
                area: [(editor.body.offsetWidth + 6) + 'px', '500px'],
                content: "<div id='pdfDom'>"+content+"</div>"
            });
            html2Canvas(document.querySelector("#pdfDom"), {
                useCORS: true
            }).then(function (canvas) {
                // canvas 裁切图片
                // var sliceCanvas = document.createElement("canvas");
                // var context = sliceCanvas.getContext('2d');
                // sliceCanvas.width = 300;
                // sliceCanvas.height = 300;
                // var imageObj = new Image();
                // // imageObj.setAttribute('crossOrigin', 'anonymous'); // 解决报错问题 failed to execute 'toDataURL' on 'HTMLCanvasElement' tainted canvaes may not be exported
                // imageObj.onload = function(options) {
                //     var width = imageObj.width;
                //     var height = imageObj.height;
                //     // draw cropped image
                //     var sourceX = 0;
                //     var sourceY = 0;
                //     var sourceWidth = width;
                //     var sourceHeight = height;
                //     var destWidth = sourceWidth;
                //     var destHeight = sourceHeight;
                //     var destX = 0;
                //     var destY = 0;
                //     context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
                //     var res = sliceCanvas.toDataURL('image/jpeg', 1.0);
                //     var img = document.createElement("img");
                //     var div = document.createElement("div");
                //     img.src = res;
                //     div.style.cssText = "position: fixed; z-index: 999; height: 500px; overflow: auto;";
                //     div.appendChild(img);
                //     document.body.appendChild(div);
                // };
                // imageObj.src = canvas.toDataURL('image/jpeg', 1.0);

                // 偏移生成a4纸全屏的pdf，不清晰
                let contentWidth = canvas.width; // canvas的宽度
                let contentHeight = canvas.height; // canvas的高度
                let pageHeight = contentWidth / 595.28 * 841.89; // 按照画布的比例，计算出的一张a4纸的高度
                let leftHeight = contentHeight;
                let position = 0;
                let imgWidth = 595.28;
                let imgHeight = 595.28 / contentWidth * contentHeight; // 按照a4纸的宽度，缩放后图片的高度
                let pageData = canvas.toDataURL('image/jpeg', 1.0);
                // var img = document.createElement("img");
                // var div = document.createElement("div");
                // img.src = pageData;
                // div.style.cssText = "position: fixed; z-index: 999; height: 500px; overflow: auto;";
                // div.appendChild(img);
                // document.body.appendChild(div);
                let PDF = new JsPDF('', 'pt', 'a4');
                if (leftHeight < pageHeight) { // 不足一张纸
                    PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
                } else {
                    while (leftHeight > 0) {
                        PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
                        leftHeight -= pageHeight;
                        position -= 841.89;
                        if (leftHeight > 0) {
                            PDF.addPage();
                        }
                    }
                }
                PDF.save(title + '.pdf');
                layer.close(layerIndex);
            }).catch(err => {
                console.log(err);
            })
        }
    }
}

